package org.rkuk.kasutil.test.framework 
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.utils.getTimer;
	import org.rkuk.kasutil.test.event.TestMethodEvent;
	import org.rkuk.kasutil.test.system.TestContext;
	
	/**
	 * ...
	 * @author rkuk
	 */
	public class TestMethod extends EventDispatcher
	{
		//whether the method to test is a static method or not
		protected var isStatic_:Boolean;
		//the name of the method to test
		protected var methodName_:String;
		//the paramters used to execute the test method
		protected var params_:Array;
		//used to record the execution time
		protected var executionTime_:int;
		//a flag indicate whether the execution process is finished or is suspended for ansy event
		protected var isExecute_:Boolean;
		//如果当前TestMethod被包含在group中，则parent指向包含其的TestMethodGroup
		private var parent_:TestMethodGroup;
		
		/**
		 * Constructor
		 * @param	methodName	the name of the method to test
		 * @param	isStatic	whether the method to test is a static method or not
		 */
		public function TestMethod(methodName:String,isStatic:Boolean)
		{
			super();
			methodName_ = methodName;
			isStatic_ = isStatic_;
			isExecute_ = false;
		}
		
		public function set params(value:Array):void 
		{
			params_ = value;
		}
		
		public function execute(testContext:TestContext):int 
		{
			var invoker:Object = getInvoker(testContext);
			
			executionTime_ = getTimer();
			invoker[methodName_].applay(invoker, params_);
			var stepTime:int = getTimer();
			notifiyExecute(true);
			
			return stepTime - executionTime_;
		}
		
		/**
		 * get which Class or instance to execute the TestMethod on, according to isStatic_
		 * @param	testContext
		 * @return
		 */
		protected function getInvoker(testContext:TestContext):Object
		{
			if (isStatic_)
				return testContext.testClass;
			else
				return testContext.testObject;
		}
		
		public function get name():String 
		{
			if (parent == null)
				return methodName_;
			else
				return parent.name + " " + methodName_;
		}
		
		public function fail(message:String):void 
		{
			notifiyExecute(false, message);
		}
		
		public function get isExecute():Boolean 
		{
			return isExecute_;
		}
		
		protected function get parent():TestMethodGroup 
		{
			return parent_;
		}
		
		protected function set parent(value:TestMethodGroup):void 
		{
			parent_ = value;
		}
		
		protected function clone():TestMethod
		{
			return new TestMethod(methodName_, isStatic_);
		}
		
		protected function equal(testMethod:TestMethod):Boolean
		{
			return methodName_ == testMethod.methodName_ && isStatic_ == testMethod.isStatic_;
		}
		
		protected function notifiyExecute(isSuccess:Boolean, message:String = "")
		{
			isExecute = true;
			dispatchEvent(new TestMethodEvent(TestMethodEvent.EXECUTE, isSuccess, getTimer() - executionTime_, message));
		}
	}
}